// SPDX-FileCopyrightText: Copyright 2025-2025 深圳市同心圆网络有限公司
// SPDX-License-Identifier: Apache-2.0

package roadmap_dao

import (
	"context"
	"sort"

	"gitcode.com/lvupclub/lvup-api/dao/common"
	"gitcode.com/lvupclub/proto-gen-go.git/src/roadmap_rag_api"
	"go.mongodb.org/mongo-driver/v2/bson"
	"go.mongodb.org/mongo-driver/v2/mongo"
	"go.mongodb.org/mongo-driver/v2/mongo/options"
)

type ChatMessageDbItem struct {
	MessageId   string                         `bson:"_id"`
	RoadmapId   string                         `bson:"roadmapId"`
	RagConfigId string                         `bson:"ragConfigId"`
	ChatRole    roadmap_rag_api.CHAT_ROLE_TYPE `bson:"chatRole"`
	Content     string                         `bson:"content"`
	TimeStamp   int64                          `bson:"timeStamp"`
	OwnerUserId string                         `bson:"ownerUserId"`
}

func (item *ChatMessageDbItem) ToChatMessage() *roadmap_rag_api.ChatMessage {
	return &roadmap_rag_api.ChatMessage{
		MessageId:   item.MessageId,
		ChatRole:    item.ChatRole,
		Content:     item.Content,
		TimeStamp:   item.TimeStamp,
		OwnerUserId: item.OwnerUserId,
	}
}

type _ChatMessageDao struct {
	mc *mongo.Collection
}

func newChatMessageDao(db *mongo.Database) (*_ChatMessageDao, error) {
	mc := db.Collection(common.DB_NS_ROADMAP + "chat_msg")
	_, err := mc.Indexes().CreateOne(context.Background(), mongo.IndexModel{
		Keys: bson.D{{"roadmapId", 1}, {"ragConfigId", 1}, {"ownerUserId", 1}, {"timeStamp", 1}},
	})
	if err != nil {
		return nil, err
	}
	return &_ChatMessageDao{mc: mc}, nil
}

func (db *_ChatMessageDao) Insert(ctx context.Context, dbItem *ChatMessageDbItem) error {
	_, err := db.mc.InsertOne(ctx, dbItem)
	return err
}

func (db *_ChatMessageDao) Exist(ctx context.Context, roadmapId, ragConfigId, messageId string) (bool, error) {
	count, err := db.mc.CountDocuments(ctx, bson.M{"roadmapId": roadmapId, "ragConfigId": ragConfigId, "_id": messageId})
	return count > 0, err
}

func (db *_ChatMessageDao) Get(ctx context.Context, roadmapId, ragConfigId, ownerUserId, messageId string) (*ChatMessageDbItem, error) {
	retItem := &ChatMessageDbItem{}
	err := db.mc.FindOne(ctx, bson.M{"roadmapId": roadmapId, "ragConfigId": ragConfigId, "ownerUserId": ownerUserId, "_id": messageId}).Decode(retItem)
	return retItem, err
}

func (db *_ChatMessageDao) Remove(ctx context.Context, roadmapId, ragConfigId, ownerUserId, messageId string) error {
	_, err := db.mc.DeleteOne(ctx, bson.M{"roadmapId": roadmapId, "ragConfigId": ragConfigId, "ownerUserId": ownerUserId, "_id": messageId})
	return err
}

func (db *_ChatMessageDao) RemoveByRagConfig(ctx context.Context, roadmapId, ragConfigId string) error {
	_, err := db.mc.DeleteMany(ctx, bson.M{"roadmapId": roadmapId, "ragConfigId": ragConfigId})
	return err
}

func (db *_ChatMessageDao) RemoveByRoadmap(ctx context.Context, roadmapId string) error {
	_, err := db.mc.DeleteMany(ctx, bson.M{"roadmapId": roadmapId})
	return err
}

func (db *_ChatMessageDao) List(ctx context.Context, roadmapId, ragConfigId, ownerUserId string, cmpTimeStamp int64, listType roadmap_rag_api.LIST_MESSAGE_TYPE, limit int64) ([]*ChatMessageDbItem, error) {
	query := bson.M{"roadmapId": roadmapId, "ragConfigId": ragConfigId, "ownerUserId": ownerUserId}
	sortOrder := 1
	if listType == roadmap_rag_api.LIST_MESSAGE_TYPE_LIST_MESSAGE_AFTER {
		query["timeStamp"] = bson.M{"$gt": cmpTimeStamp}
		sortOrder = 1
	} else if listType == roadmap_rag_api.LIST_MESSAGE_TYPE_LIST_MESSAGE_BEFORE {
		query["timeStamp"] = bson.M{"$lt": cmpTimeStamp}
		sortOrder = -1
	}

	cursor, err := db.mc.Find(ctx, query, options.Find().SetLimit(limit).SetSort(bson.M{"timeStamp": sortOrder}))
	if err != nil {
		return nil, err
	}
	retList := []*ChatMessageDbItem{}
	err = cursor.All(ctx, &retList)
	if err != nil {
		return nil, err
	}
	sort.Sort(ChatMessageList(retList))
	return retList, nil
}

type ChatMessageList []*ChatMessageDbItem

func (l ChatMessageList) Len() int {
	return len(l)
}

func (l ChatMessageList) Less(i, j int) bool {
	return l[i].TimeStamp < l[j].TimeStamp
}

func (l ChatMessageList) Swap(i, j int) {
	l[i], l[j] = l[j], l[i]
}
